﻿// FogBugz Community Case List Plugin
// ----------------------------------
// 
// Copyright 2010, 2011 by Sirius Technologies AG / Arsène von Wyss - avw@gmx.ch
// 
// Development has been sponsered by Sirius Technologies AG, Basel
//
// Source:
// 
// https://communitycaselist.googlecode.com/hg/
// 
// License:
// 
// The library is distributed under the GNU Lesser General Public License:
// http://www.gnu.org/licenses/lgpl.html
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Thanks to FogCreek for contributing a fix! :)

using System;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;

namespace Sirius.CommunityCaseList {
	public class CTicket {
		private const int cTicketLength = 16;
		private static readonly Random rnd = new Random();

		// groups:
		// 1: "removed_" or none
		// 2: case number
		// 3: full ticket password, 8 or 16 alphanumeric characters
		// 4: single-case password, if it's a 16 character format sTicket (ignore)
		private static readonly Regex ticketParser =
				new Regex(@"^(removed_)?([1-9][0-9]*)_(([0-9a-z]{8}){1,2})$",
						RegexOptions.CultureInvariant|RegexOptions.IgnoreCase);

		public static string GenerateTicket(int ixBug) {
			StringBuilder result = new StringBuilder(cTicketLength+10);
			result.Append(ixBug.ToString(CultureInfo.InvariantCulture));
			result.Append('_');
			for (int i = 0; i < cTicketLength; i++) {
				result.Append(GetTicketChar());
			}
			return result.ToString();
		}

		public static string GetSingleCaseTicketFromMulti(string sTicketMultiCase) {
			CTicket ticket = new CTicket(sTicketMultiCase);
			return ticket.sTicketSingleCase;
		}

		private static char GetTicketChar() {
			return "0123456789abcdefghijklmnopqrstuv"[rnd.Next(32)];
		}

		public static bool IsTicketValid(string sTicket) {
			CTicket ticket = new CTicket(sTicket);
			return ticket.fIsValid;
		}

		private readonly bool _fIsValid;
		private readonly bool _fPrivate;
		private readonly int _ixBug;
		private readonly string _sPasswordMultiCase;
		private readonly string _sTicket;

		public CTicket(string sTicket) {
			_sTicket = sTicket;
			Match match = ticketParser.Match(sTicket);
			if (match.Success) {
				_fIsValid = true;
				_ixBug = int.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture);
				_sPasswordMultiCase = match.Groups[3].Value;
				_fPrivate = match.Groups[1].Success;
			}
		}

		public bool fIsValid {
			get {
				return _fIsValid;
			}
		}

		public bool fPrivate {
			get {
				return _fPrivate;
			}
		}

		public int ixBug {
			get {
				return _ixBug;
			}
		}

		public string sPasswordMultiCase {
			get {
				return _sPasswordMultiCase;
			}
		}

		public string sPasswordSingleCase {
			get {
				return sPasswordMultiCase.Substring(0, (sPasswordMultiCase.Length/2));
			}
		}

		public string sTicketMultiCase {
			get {
				return String.Format(CultureInfo.InvariantCulture, "{0}_{1}",
						ixBug,
						sPasswordMultiCase);
			}
		}

		public string sTicketSingleCase {
			get {
				return String.Format(CultureInfo.InvariantCulture, "{0}_{1}",
						ixBug,
						sPasswordSingleCase);
			}
		}

		public string GetPrivateTicket() {
			return "removed_"+sTicketMultiCase;
		}

		public override string ToString() {
			return _sTicket;
		}
	}
}
